package com.itheima.wms.common.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class CrudServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements ICrudService<T> {

    private static String[] queryArray = {"gt_", "ge_", "lt_", "le_", "in_", "like_", "likeRight_", "likeLeft_"};
    private static List<String> keyIgnore = ImmutableList.of("ascs", "descs", "current", "size", "_t");

    protected Wrapper<T> getWrapper(SFunction<T, ?> column, Object value) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null != value, column, value);
        return wrapper;
    }

    protected Wrapper<T> getWrapper(Map<String, Object> data) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        finalWrapper(wrapper, data);
        return wrapper;
    }

    public void finalWrapper(QueryWrapper<T> wrapper, Map<String, Object> params) {
        if (CollectionUtils.isEmpty(params)) {
            return;
        }
        Class cls = QueryWrapper.class;
        for (String key : params.keySet()) {
            if (keyIgnore.contains(key)) {
                continue;
            }
            Object value = params.get(key);
            if (value == null || StringUtils.isBlank(value.toString())) {
                continue;
            }

            if (key.indexOf("_") <= 0) {
                wrapper.eq(upperCharToUnderLine(key), value);
                continue;
            }

            for (String querykey : queryArray) {
                if (key.startsWith(querykey)) {
                    Method method = null;
                    try {
                        if (value instanceof Collection) {
                            method = cls.getMethod(querykey.replaceFirst("_", ""), Object.class, Collection.class);
                        } else {
                            method = cls.getMethod(querykey.replaceFirst("_", ""), Object.class, Object.class);
                        }
                        method.invoke(wrapper, upperCharToUnderLine(key.replaceFirst(querykey, "")), value);
                        break;
                    } catch (Exception e) {
                        log.info("拼接 wrapper 异常", e);
                    }
                }
            }
        }
        //排序字段
        String ascs = (String) params.get("ascs");
        String descs = (String) params.get("descs");
        //前端字段排序
        if (StringUtils.isNotBlank(ascs)) {
            wrapper.orderByAsc(upperCharToUnderLine(ascs));
        }
        if (StringUtils.isNotBlank(descs)) {
            wrapper.orderByDesc(upperCharToUnderLine(descs));
        }
    }

    private String upperCharToUnderLine(String param) {
        Pattern p = Pattern.compile("[A-Z]");
        if (param == null || param.equals("")) {
            return "";
        }
        StringBuilder builder = new StringBuilder(param);
        Matcher mc = p.matcher(param);
        int i = 0;
        while (mc.find()) {
            builder.replace(mc.start() + i, mc.end() + i, "_" + mc.group().toLowerCase());
            i++;
        }

        if ('_' == builder.charAt(0)) {
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }

    public <E extends IPage<T>> E page(E page, Map data) {
        Wrapper<T> wrapper = getWrapper(data);
        return page(page, wrapper);
    }

    public List<T> list(Map data) {
        Wrapper<T> wrapper = getWrapper(data);
        return list(wrapper);
    }


    public T getOne(String column, Object value) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        wrapper.eq(column, value);
        return this.getOne(wrapper);
    }
}
